using System;
using System.Collections.Generic;
using System.Reflection;
using NFreeMarker.Template;

namespace NFreeMarker.Ext.Beans
{
    /**
     * A class that will wrap a reflected method call into a
     * {@link freemarker.template.TemplateMethodModel} interface. 
     * It is used by {@link BeanModel} to wrap reflected method calls
     * for overloaded methods.
     * @author Attila Szegedi, szegedia at users dot sourceforge dot net
     * @version $Id: OverloadedMethodModel.java,v 1.25 2005/06/11 12:12:04 szegedia Exp $
     */
    class OverloadedMethodModel : ITemplateMethodModelEx, ITemplateSequenceModel
    {
        private readonly object _object;
        private readonly MethodMap _methodMap;
        
        public OverloadedMethodModel(object obj, MethodMap methodMap)
        {
            _object = obj;
            _methodMap = methodMap;
        }

        /**
         * Invokes the method, passing it the arguments from the list. The actual
         * method to call from several overloaded methods will be chosen based
         * on the classes of the arguments.
         * @throws TemplateModelException if the method cannot be chosen
         * unambiguously.
         */
        public object Exec(IList<ITemplateModel> arguments)
        {
            MemberAndArguments maa = _methodMap.GetMemberAndArguments(arguments);
            var method = (MethodInfo) maa.GetMember();
            try
            {
                return _methodMap.GetWrapper().InvokeMethod(_object, method, maa.GetArgs());
            }
            catch (Exception e)
            {
                //while (e is InvocationTargetException)
                //{
                //    Throwable t = ((InvocationTargetException)e).getTargetException();
                //    if (t is Exception)
                //    {
                //        e = (Exception)t;
                //    }
                //    else
                //    {
                //        break;
                //    }
                //}
                //if (method.IsStatic)
                //{
                //    throw new TemplateModelException("Method " + method + 
                //            " threw an exception", e);
                //}
                //else
                //{
                //    var buf = new StringBuilder();
                //    object[] args = maa.GetArgs();
                //    foreach (object arg in args)
                //    {
                //        buf.Append(arg == null ? "null" : arg.GetType().FullName).Append(',');
                //    }
                //    throw new TemplateModelException("Method " + method + 
                //            " threw an exception when invoked on " + _object + 
                //            " with arguments of types [" + buf + "]", e);
                //}

                throw new NotImplementedException();
            }
        }

        public object Exec(IList<string> arguments)
        {
            throw new NotSupportedException();
        }

        public ITemplateModel Get(int index)
        {
            //return (ITemplateModel) Exec(Collections12.singletonList(
            //        new SimpleNumber(index)));
            throw new NotImplementedException();
        }

        public int Size()
        {
            throw new TemplateModelException("?size is unsupported for: " + 
                    GetType().FullName);
        }
    }
}